package com.itheima.stock.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.github.pagehelper.util.StringUtil;
import com.itheima.stock.constant.StockConstant;
import com.itheima.stock.mapper.SysUserMapper;
import com.itheima.stock.pojo.entity.SysUser;
import com.itheima.stock.service.UserService;
import com.itheima.stock.utils.IdWorker;
import com.itheima.stock.vo.req.LoginReqVo;
import com.itheima.stock.vo.resp.LoginRespVo;
import com.itheima.stock.vo.resp.R;
import com.itheima.stock.vo.resp.ResponseCode;
import com.sun.glass.ui.View;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 定义用户服务实现
 */
@Service("userService")
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 根据用户名查询用户信息
     * @param userName
     * @return
     */

    @Override
    public SysUser findByUserName(String userName) {
        return sysUserMapper.findUserInfoByUserName(userName);
    }

    /**
     * 用户登录功能
     * @param reqVo
     * @return
     */
    @Override
    public R<LoginRespVo> login(LoginReqVo reqVo) {
        //判断输入参数的合法性
        if(reqVo == null || StringUtils.isBlank(reqVo.getUsername()) || StringUtils.isBlank(reqVo.getPassword())) {
            return R.error(ResponseCode.USERNAME_OR_PASSWORD_ERROR);
        }
        // 判断验证码是否存在
        if(StringUtils.isBlank(reqVo.getCode()) || StringUtils.isBlank(reqVo.getSessionId())){
            return R.error(ResponseCode.CHECK_CODE_ERROR);
        }
        // 判断Redis中保存的验证码与输入的验证码是否相同（比较时忽略大小写）
        String redisCode = (String) redisTemplate.opsForValue().get(StockConstant.CHECK_PREFIX + reqVo.getSessionId());
        // 验证码过期
        if (StringUtils.isBlank(redisCode)) {
            R.error(ResponseCode.CHECK_CODE_EXPIRED);
        }
        // 验证码错误
        if (!redisCode.equalsIgnoreCase(reqVo.getCode())) {
            R.error(ResponseCode.CHECK_CODE_ERROR);
        }
        //根据用户名查询用户信息
        SysUser dbUser = sysUserMapper.findUserInfoByUserName(reqVo.getUsername());
        //判断用户是否存在 或 明文密码和密文对应不上
        if (dbUser == null || !passwordEncoder.matches(reqVo.getPassword(), dbUser.getPassword())) {
            return R.error(ResponseCode.USERNAME_OR_PASSWORD_ERROR);
        }
        //构建响应对象
        LoginRespVo respVo = new LoginRespVo();
//        respVo.setUsername(dbUser.getUsername());
//        respVo.setNickname(dbUser.getNickName());
//        respVo.setPassword(dbUser.getPassword());
//        respVo.setPhone(dbUser.getPhone());
        //我们发现respVo与dbUser下具有相同的属性，所以直接复制即可
        BeanUtils.copyProperties(dbUser, respVo);
        return R.ok(respVo);
    }

    /**
     * 生成图片验证码功能
     * @return
     */
    @Override
    public R<Map>  getCaptchaCode() {
        /**
         * 1、生成图片验证码对象
         * 参数1：图片宽度
         * 参数2：图片高度
         * 参数3：验证码位数
         * 参数4：干扰线的数量
         */
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(250, 40, 4, 5);
        // 设置校验码背景
        captcha.setBackground(Color.LIGHT_GRAY);
        // 获取图片验证码
        String checkCode = captcha.getCode();
        // 获取base64图片字符串
        String imageData = captcha.getImageBase64();
        /**
         * 2、生成 sessionId
         * 避免前端转换精度丢失
         */
        String sessionId = String.valueOf(idWorker.nextId());
        log.info("当前生成的图片验证码{}，会话ID{}", checkCode, sessionId);
        /**
         * 3、将sessionId作为 key,验证码值作为 value 保存到 redis 中，并设置过期时间
         */
        redisTemplate.opsForValue().set(StockConstant.CHECK_PREFIX +sessionId, checkCode, 5, TimeUnit.MINUTES);
        /**
         * 4、组装数据
         */
        Map<String, String> data = new HashMap();
        data.put("imageData", imageData);
        data.put("sessionId", sessionId);
        /**
         * 5、响应数据
         */
        return R.ok(data);
    }
}
